home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / util / boot / WBTitle14.lha / WBTitle / Source / WBTitle.c < prev    next >
C/C++ Source or Header  |  1995-05-26  |  16KB  |  591 lines

  1. /*
  2.  * WBTitle
  3.  *
  4.  * Version 1.4
  5.  *
  6.  * v1.0   Original public release by Mark Thomas
  7.  *
  8.  * v1.3d  German locale version by Martin Kaim (Gwardar), fixes/features:
  9.  * - removed a bug in the numeric display routine (v1.0 would print e.g. 10,274,380 as
  10.  *   :,274,380 )
  11.  * - now ToolType SEPARATOR is spelled correctly (instead of SEPERATOR),
  12.  *   also the default separator for German locale now is '.' instead of ','
  13.  * - supplied smakefile
  14.  * - version now works with the German locale (ONLY) (different Workbench title bar)
  15.  *   (can/must be adjusted to any other locale by slight changes in the source and
  16.  *   recompiling)
  17.  * - supplied Icon with a nice tooltype setting (in German only)
  18.  * - adjusted documentation to reflect these changes
  19.  *
  20.  * v1.4   Multi-locale update by Gwardar, changes/features: 
  21.  *
  22.  *   This version *finally* supports ALL locales by using two new ToolType entries!
  23.  *
  24.  * - Switched back to English locale as *default* configuration (convenient for the
  25.  *   English-speaking Amiga community :-)
  26.  * - You can now configure this program to *whatever* your original Workbench title
  27.  *   might read, so WBTitle is *no longer* limited to English- or German-speaking users
  28.  *   :-)
  29.  * - Supplied 2 icons with appropriate tooltype entries for English and German locales.
  30.  * - Now compiled with SAS/C v6.55 (which increases the excutable size by ~120 bytes)
  31.  *   but nevertheless the patch is worth it.
  32.  *
  33.  * - Adjusted docs to reflect changes.
  34.  *
  35.  * - NB: allows for up to 2^32 - 1 bytes (~4 GB) of memory (who knows, in a few
  36.  *   years from now this *might* be the standard virtual memory amount on Amigas) ;->
  37.  * 
  38.  * Public Domain Software
  39.  *
  40.  * This program replaces the Amiga's Workbench title bar so that it shows the amount
  41.  * of all types of FREE memory currently available: Chip, Fast, Public; 
  42.  * further VMM (if installed and ACTIVE), and Retina Gfx board memory (if applicable).
  43.  */
  44.  
  45. #include <string.h>
  46. #include <ctype.h>
  47.  
  48. #include <exec/types.h>
  49. #include <exec/memory.h>
  50. #include <intuition/intuition.h>
  51. #include <dos/dos.h>
  52.  
  53. #include <proto/exec.h>
  54. #include <proto/intuition.h>
  55. #include <proto/dos.h>
  56. #include <proto/retina.h>
  57.  
  58. // Gwardar begin
  59. //#include <proto/vmm.h>                // Gwardar: if you don't have the proto file,
  60.                                         // so what? It's not really needed.
  61. #include <pragmas/retina_pragmas.h>     // Gwardar: you may comment this out, if
  62.                                         // you don't have the Retina stuff
  63. // Gwardar end
  64.  
  65. #include <clib/alib_protos.h>
  66.  
  67. // The SetWindowTitles function offset
  68. #define SWTOffset -276
  69.  
  70. enum {
  71.     JMPINSTR = 0x4ef9
  72. };
  73.  
  74. typedef struct JmpEntry {
  75.     UWORD Instr;
  76.     APTR Func;
  77. } JmpEntry;
  78.  
  79. static BOOL Replace(void);
  80. static void Restore(void);
  81. static void __asm new_SetWindowTitles(register __a0 struct Window *,
  82.                     register __a1 UBYTE *, register __a2 UBYTE *,
  83.                     register __a6 struct Library *);
  84. static void NumberToString(ULONG number);
  85. static void format_number(ULONG number);
  86. static void no_lead_triple(ULONG number);
  87. static void lead_triple(ULONG number);
  88.  
  89. // Gwardar begin
  90. //ULONG AvailVMem(ULONG);
  91. ULONG Retina_AvailMem(ULONG);
  92. // Gwardar end
  93.  
  94. // Global variables
  95. struct RetinaBase *RetinaBase;
  96. struct Library *VMMBase;
  97.  
  98. // Local variables
  99. static char verstring[] = "$VER: WBTitle 1.4 (multi-locale version by Gwardar) " __AMIGADATE__;
  100. static char port_name[] = "WBTitle";
  101.  
  102. static void __asm (*old_SetWindowTitles)(register __a0 struct Window *,
  103.                                                register __a1 UBYTE *,
  104.                             register __a2 UBYTE *,
  105.                             register __a6 struct Library *);
  106. static JmpEntry *SWTEntry;
  107. // Gwardar begin
  108. static char *match1_str, *match2_str;
  109. // Gwardar end
  110. static char *chip_str, *fast_str, *public_str, *total_str, *virtual_str;
  111. static char *retina_str, *memorder_str, *prefix_str, *suffix_str, *labels_str;
  112. static char *comma_str, *mem_str, *last_str, *buff_ptr;
  113. static char num_buf[16], comma;
  114. static int units, num_size, mem_str_len, prefix_str_len;
  115. static BOOL sep1000, labels_after;
  116.  
  117. /*
  118.  * The main method for replacing an Amiga OS function as safe as
  119.  * possible is to place the function with a jump table that is
  120.  * allocated.  While the function is replaced, the jump table simply
  121.  * jumps to my routine:
  122.  *
  123.  * jmp  _new_SetWindowTitles
  124.  *
  125.  * When the user asks the program to quit, we can't simply put the
  126.  * pointer back that SetFunction() gives us since someone else might
  127.  * have replaced the function.  So, we first see if the pointer we
  128.  * get back points to the out jump table.  If so, then we _can_ put
  129.  * the pointer back like normal (no one has replaced the function
  130.  * while we has it replaced).  But if the pointer isn't mine, then
  131.  * we have to replace the jump table function pointer to the old
  132.  * function pointer:
  133.  *
  134.  * jmp  _old_SetWindowTitles
  135.  *
  136.  * Finally, we only deallocate the jump table _if_ we did not have
  137.  * to change the jump table.
  138.  */
  139.  
  140. main(int argc, char *argv[])
  141. {
  142.     struct MsgPort *port;
  143.  
  144.     // FindPort() Forbid()
  145.     Forbid();
  146.  
  147.     port = FindPort(port_name);
  148.     if (port) {
  149.         struct MsgPort *reply_port;
  150.  
  151.         // Create a reply port
  152.         reply_port = CreateMsgPort();
  153.         if (reply_port) {
  154.             struct Message msg;
  155.  
  156.             // Set fields in message structure
  157.             msg.mn_ReplyPort = reply_port;
  158.             msg.mn_Length = sizeof(struct Message);
  159.  
  160.             // Send the message
  161.             PutMsg(port, &msg);
  162.  
  163.             // Finished with port, so stop FindPort() Forbid()
  164.             Permit();
  165.  
  166.             // Wait for a reply
  167.             do {
  168.                 WaitPort(reply_port);
  169.             } while (GetMsg(reply_port) == NULL);
  170.  
  171.             // Clear and Delete reply_port Forbid()
  172.             Forbid();
  173.  
  174.             // Clear any messages
  175.             while (GetMsg(reply_port));
  176.  
  177.             // Delete the reply port
  178.             DeleteMsgPort(reply_port);
  179.  
  180.             // Clear and Delete reply_port stop Forbid()
  181.             Permit();
  182.         } else {
  183.             // Finished with port, so stop FindPort() Forbid()
  184.             Permit();
  185.         }
  186.     } else if (port = CreateMsgPort()) {
  187.         struct Message *msg;
  188.         char **ttypes;
  189.  
  190.         // Finished with port, so stop FindPort() Forbid()
  191.         Permit();
  192.  
  193.         // Setup quitting port
  194.         port->mp_Node.ln_Name = port_name;
  195.         port->mp_Node.ln_Pri = -120;
  196.  
  197.         // Add quitting port to public list
  198.         AddPort(port);
  199.  
  200.         // Open the Retina library
  201.         RetinaBase = (struct RetinaBase *)OpenLibrary("retina.library", 0);
  202.  
  203.         // Check on VMM (only if ACTIVE!): look for port, and open lib
  204.         if (FindPort("VMM_Port")) {
  205.             VMMBase = OpenLibrary("vmm.library", 0);
  206.         }
  207.  
  208.         // Setup to read some arguments
  209.         ttypes = ArgArrayInit(argc, argv);
  210.  
  211.         // Read some arguments
  212.                 
  213.                 // Gwardar begin
  214.                 // these two new tooltypes allow for the multi-locale support
  215.                 // by enabling you to change the matching strings via tooltype entries
  216.                 match1_str = ArgString(ttypes, "MATCH1", "Amiga");              //default match 1 = "Amiga"
  217.                 match2_str = ArgString(ttypes, "MATCH2", "graphics mem");       //default match 2 = "graphics mem"
  218.                 // Gwardar end
  219.         prefix_str = ArgString(ttypes, "PREFIX", "");   // Gwardar: default = ""
  220.         suffix_str = ArgString(ttypes, "SUFFIX", "");
  221.         labels_str = ArgString(ttypes, "LABELS", "AFTER");
  222.  
  223.         chip_str = ArgString(ttypes, "CHIP", " Chip  ");
  224.         fast_str = ArgString(ttypes, "FAST", " Fast  ");
  225.         public_str = ArgString(ttypes, "PUBLIC", " Public  ");
  226.         total_str = ArgString(ttypes, "TOTAL", " Total  ");
  227.         virtual_str = ArgString(ttypes, "VIRTUAL", " Virtual  ");
  228.         retina_str = ArgString(ttypes, "RETINA", " Retina  ");
  229.  
  230.         memorder_str = ArgString(ttypes, "MEMORDER", "CVPR");
  231.         sep1000 = (ArgString(ttypes, "THOUSANDSEP", NULL) != NULL);
  232.         units = ArgInt(ttypes, "UNITS", 1);
  233.         comma_str = ArgString(ttypes, "SEPARATOR", NULL);
  234.         if (comma_str && comma_str[0]) {
  235.             comma = comma_str[0];
  236.         } else {
  237.             comma = ',';   // separator defaults to ',' for English locale 
  238.         }
  239.  
  240.         labels_after = (stricmp(labels_str, "BEFORE") != 0);
  241.         if (units < 0) {
  242.             units = 1;
  243.         }
  244.  
  245.         // Compute the size of numbers
  246.         {
  247.             ULONG maxnum = 0xffffffff;
  248.  
  249.             // Compute the number of digits
  250.             maxnum /= units;
  251.             while (maxnum) {
  252.                 maxnum /= 10;
  253.                 num_size++;
  254.             }
  255.  
  256.             // Compute the number of commas
  257.             if (sep1000) {
  258.                 int com = num_size;
  259.                 while (com > 3) {
  260.                     num_size++;
  261.                     com -= 3;
  262.                 }
  263.             }
  264.         }
  265.  
  266.         // Compute the size of the mem string
  267.         {
  268.             ULONG i = 0;
  269.             char ch;
  270.  
  271.             // Add in the prefix string size
  272.             mem_str_len = prefix_str_len = strlen(prefix_str);
  273.  
  274.             // Add in the memory parts
  275.             while (ch = toupper(memorder_str[i])) {
  276.                 switch (ch) {
  277.                     case 'C':
  278.                         mem_str_len += strlen(chip_str) + num_size;
  279.                         break;
  280.                     case 'F':
  281.                         mem_str_len += strlen(fast_str) + num_size;
  282.                         break;
  283.                     case 'P':
  284.                         mem_str_len += strlen(public_str) + num_size;
  285.                         break;
  286.                     case 'T':
  287.                         mem_str_len += strlen(total_str) + num_size;
  288.                         break;
  289.                     case 'V':
  290.                         if (VMMBase) {
  291.                             mem_str_len += strlen(virtual_str) + num_size;
  292.                         }
  293.                         break;
  294.                     case 'R':
  295.                         if (RetinaBase) {
  296.                             mem_str_len += strlen(retina_str) + num_size;
  297.                         }
  298.                         break;
  299.                 }
  300.                 i++;
  301.             }
  302.  
  303.             // Add in the suffix string size
  304.             mem_str_len += strlen(suffix_str);
  305.         }
  306.  
  307.         if (mem_str_len > 0) {
  308.             // Allocate the memory
  309.             mem_str = AllocMem(mem_str_len + 1, MEMF_PUBLIC);
  310.             if (mem_str) {
  311.                 strcpy(mem_str, prefix_str);
  312.                 last_str = &mem_str[prefix_str_len];
  313.  
  314.                 // Attempt to replace function
  315.                 if (Replace()) {
  316.                     // Wait for someone to signal me to quit
  317.                                         // e.g. WBTitle started again
  318.                     do {
  319.                         WaitPort(port);
  320.                         msg = GetMsg(port);
  321.                     } while (msg == NULL);
  322.                     ReplyMsg(msg);
  323.  
  324.                     // Restore function
  325.                     Restore();
  326.                 }
  327.                 FreeMem(mem_str, mem_str_len + 1);
  328.             }
  329.         }
  330.  
  331.         // Cleanup from reading arguments
  332.         ArgArrayDone();
  333.  
  334.         // Remove port from public access
  335.         RemPort(port);
  336.  
  337.         // Clear and Delete port Forbid()
  338.         Forbid();
  339.  
  340.         // Clear the port of messages
  341.         while (msg = GetMsg(port)) {
  342.             ReplyMsg(msg);
  343.         }
  344.  
  345.         // Closedown quitting port
  346.         DeleteMsgPort(port);
  347.  
  348.         // Clear and Delete port stop Forbid()
  349.         Permit();
  350.     }
  351. }
  352.  
  353. static BOOL Replace(void)
  354. {
  355.     // Allocate the jump table
  356.     SWTEntry = AllocMem(sizeof(JmpEntry), 0);
  357.     if (SWTEntry) {
  358.         // Replacement Forbid()
  359.         Forbid();
  360.  
  361.         // Replace the function with pointer to jump table
  362.         old_SetWindowTitles = SetFunction((struct Library *)IntuitionBase,
  363.                                             SWTOffset, (ULONG (*)())SWTEntry);
  364.  
  365.         // Setup the jump table
  366.         SWTEntry->Instr = JMPINSTR;
  367.         SWTEntry->Func = new_SetWindowTitles;
  368.  
  369.         // Clear the CPU's cache so the execution cache is valid
  370.         CacheClearU();
  371.  
  372.         // Stop the replacement Forbid()
  373.         Permit();
  374.  
  375.         return TRUE;
  376.     } else {
  377.         return FALSE;
  378.     }
  379. }
  380.  
  381. static void Restore(void)
  382. {
  383.     BOOL my_table;
  384.     ULONG (*func)();
  385.  
  386.     // Fix back Forbid()
  387.     Forbid();
  388.  
  389.     // Put old pointer back and get current pointer at same time
  390.     func = SetFunction((struct Library *)IntuitionBase, SWTOffset,
  391.                     (ULONG (*)())old_SetWindowTitles);
  392.  
  393.     // Check to see if the pointer we get back is ours
  394.     if ((JmpEntry *)func != SWTEntry) {
  395.         // If not, leave jump table in place
  396.         my_table = FALSE;
  397.         SetFunction((struct Library *)IntuitionBase, SWTOffset,
  398.                     func);
  399.         SWTEntry->Func = old_SetWindowTitles;
  400.     } else {
  401.         // If so, free the jump table
  402.         my_table = TRUE;
  403.         FreeMem(SWTEntry, sizeof(JmpEntry));
  404.     }
  405.  
  406.     // Clear the CPU's cache so the execution cache is valid
  407.     CacheClearU();
  408.  
  409.     // Stop fix back Forbid()
  410.     Permit();
  411.  
  412.     // Let the user know if the jump table couldn't be freed
  413.     if (!my_table) {
  414.         DisplayBeep(NULL);
  415.     }
  416.  
  417.     // Wait 5 seconds to try and guarantee that all tasks have
  418.     // finished executing inside my replacement function before
  419.     // quitting.  There's no real way to guarantee, though.
  420.     Delay(250);
  421. }
  422.  
  423. static void __saveds __asm new_SetWindowTitles(
  424.                         register __a0 struct Window *window,
  425.                         register __a1 UBYTE *win_title,
  426.                         register __a2 UBYTE *scr_title,
  427.                         register __a6 struct Library *lib)
  428. {
  429.     // try to make sure only the Workbench title bar gets fixed
  430.       
  431.         // Gwardar begin
  432.         // compares the title bar to contain both the string specified by
  433.         // tooltype MATCH1 (defaults to: "Amiga") and the string specified by
  434.         // tooltype MATCH2 (defaults to: "graphics mem") and may thus be adjusted
  435.         // to ANY locale/Workbench environment *without* the need to change the
  436.         // source and recompile.
  437.         
  438.         // the default matches '#??Amiga (#??.)#??.??? graphics mem#??' 
  439.         // (contained in the original Workbench's title bar in English locale)
  440.         // Gwardar end
  441.         
  442.         if (scr_title && (scr_title != (UBYTE *)0xffffffff) &&
  443.             strstr(scr_title, match1_str) && strstr(scr_title, match2_str)) {
  444.         ULONG i = 0;
  445.         char ch;
  446.  
  447.         // Set last_str to nothing
  448.         *last_str = 0;
  449.  
  450.         // Add in the memory parts
  451.         while (ch = toupper(memorder_str[i])) {
  452.             switch (ch) {
  453.                 case 'C':
  454.                     if (!labels_after) {
  455.                         strcat(last_str, chip_str);
  456.                     }
  457.                     NumberToString(AvailMem(MEMF_CHIP));
  458.                     strcat(last_str, num_buf);
  459.                     if (labels_after) {
  460.                         strcat(last_str, chip_str);
  461.                     }
  462.                     break;
  463.                 case 'F':
  464.                     if (!labels_after) {
  465.                         strcat(last_str, fast_str);
  466.                     }
  467.                     NumberToString(AvailMem(MEMF_FAST));
  468.                     strcat(last_str, num_buf);
  469.                     if (labels_after) {
  470.                         strcat(last_str, fast_str);
  471.                     }
  472.                     break;
  473.                 case 'P':
  474.                     if (!labels_after) {
  475.                         strcat(last_str, public_str);
  476.                     }
  477.                     NumberToString(AvailMem(MEMF_PUBLIC));
  478.                     strcat(last_str, num_buf);
  479.                     if (labels_after) {
  480.                         strcat(last_str, public_str);
  481.                     }
  482.                     break;
  483.                 case 'T':
  484.                     if (!labels_after) {
  485.                         strcat(last_str, total_str);
  486.                     }
  487.                     NumberToString(AvailMem(0));
  488.                     strcat(last_str, num_buf);
  489.                     if (labels_after) {
  490.                         strcat(last_str, total_str);
  491.                     }
  492.                     break;
  493.                 case 'V':
  494.                     if (VMMBase) {
  495.                         if (!labels_after) {
  496.                             strcat(last_str, virtual_str);
  497.                         }
  498.                         NumberToString(AvailVMem(0));
  499.                         strcat(last_str, num_buf);
  500.                         if (labels_after) {
  501.                             strcat(last_str, virtual_str);
  502.                         }
  503.                     }
  504.                     break;
  505.                 case 'R':
  506.                     if (RetinaBase) {
  507.                         if (!labels_after) {
  508.                             strcat(last_str, retina_str);
  509.                         }
  510.                         NumberToString(Retina_AvailMem(0));
  511.                         strcat(last_str, num_buf);
  512.                         if (labels_after) {
  513.                             strcat(last_str, retina_str);
  514.                         }
  515.                     }
  516.                     break;
  517.             }
  518.             i++;
  519.         }
  520.         strcat(last_str, suffix_str);
  521.         old_SetWindowTitles(window, win_title, mem_str, lib);
  522.     }
  523.         else    // leave other windows' titles untouched
  524.         {
  525.                 old_SetWindowTitles(window, win_title, scr_title, lib);
  526.     }
  527.         
  528. }
  529.  
  530. /*
  531.  * Convert the number to a string in the format the user specified.
  532.  * The string generated is 0 terminated.
  533.  *
  534.  * Uses global variables: buff_ptr, num_buff
  535.  *
  536.  */
  537.  
  538. static void NumberToString(ULONG number)
  539. {
  540.     number /= units;
  541.     if (sep1000) {
  542.         buff_ptr = num_buf;
  543.         format_number(number);
  544.         *buff_ptr = 0;
  545.     } else {
  546.         stcul_d(num_buf, number);
  547.     }
  548. }
  549.  
  550. // Gwardar: Functions below use recursive calls, so take heed when changing anything
  551. // within 'format_number' or 'no_lead_triple' (danger of trashing unallocated memory
  552. // when the string buffer boundary is not respected)
  553.  
  554. static void format_number(ULONG number)
  555. {
  556.     if (number > 1000) {
  557.         format_number(number / 1000);
  558.         lead_triple(number % 1000);
  559.     } else {
  560.         no_lead_triple(number);
  561.     }
  562. }
  563.  
  564. static void no_lead_triple(ULONG number)
  565. {
  566.     if (number > 10) {
  567.         no_lead_triple(number / 10);
  568.         *buff_ptr++ = ((number % 10) | 0x30);
  569.     } 
  570.         // Gwardar begin
  571.         else if (number == 10) { 
  572.                 *buff_ptr++ = (1 | 0x30); // fixes the ':' numeric display bug that v1.0
  573.                 *buff_ptr++ = (0 | 0x30); // showed on some memory amounts
  574.         }
  575.         // Gwardar end
  576.         else  // if (number < 10) // removed by Gwardar (smaller code, faster)
  577.         {
  578.         *buff_ptr++ = (number | 0x30);
  579.     }
  580. }
  581.  
  582. static void lead_triple(ULONG number)
  583. {
  584.     *buff_ptr++ = comma;
  585.     *buff_ptr++ = ((number / 100) | 0x30);
  586.     number %= 100;
  587.     *buff_ptr++ = ((number / 10) | 0x30);
  588.     number %= 10;
  589.     *buff_ptr++ = (number | 0x30);
  590. }
  591.